package com.alan.camunda.boot.config;

import org.camunda.bpm.engine.BpmnParseException;
import org.camunda.bpm.engine.HistoryService;
import org.camunda.bpm.engine.IdentityService;
import org.camunda.bpm.engine.ManagementService;
import org.camunda.bpm.engine.ProcessEngine;
import org.camunda.bpm.engine.ProcessEngineConfiguration;
import org.camunda.bpm.engine.RepositoryService;
import org.camunda.bpm.engine.RuntimeService;
import org.camunda.bpm.engine.TaskService;
import org.camunda.bpm.engine.impl.bpmn.parser.BpmnParseListener;
import org.camunda.bpm.engine.impl.cfg.CompositeProcessEnginePlugin;
import org.camunda.bpm.engine.impl.cfg.ProcessEngineConfigurationImpl;
import org.camunda.bpm.engine.impl.cfg.ProcessEnginePlugin;
import org.camunda.bpm.engine.impl.cfg.StandaloneInMemProcessEngineConfiguration;
import org.camunda.bpm.engine.impl.history.handler.CompositeHistoryEventHandler;
import org.camunda.bpm.engine.impl.history.handler.DbHistoryEventHandler;
import org.camunda.bpm.engine.impl.interceptor.Command;
import org.camunda.bpm.engine.impl.interceptor.CommandInterceptor;
import org.camunda.bpm.engine.impl.interceptor.ProcessApplicationContextInterceptor;
import org.camunda.bpm.engine.spring.SpringExpressionManager;
import org.camunda.bpm.engine.spring.SpringProcessEngineConfiguration;
import org.camunda.bpm.engine.spring.SpringTransactionContextFactory;
import org.camunda.bpm.engine.spring.SpringTransactionInterceptor;
import org.camunda.bpm.spring.boot.starter.event.PublishDelegateParseListener;
import org.camunda.bpm.spring.boot.starter.event.PublishHistoryEventHandler;
import org.camunda.bpm.spring.boot.starter.property.EventingProperty;
import org.camunda.bpm.spring.boot.starter.util.CamundaSpringBootUtil;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.support.TransactionTemplate;

import java.util.ArrayList;
import java.util.List;


/**
 * 这个类用来引入 自定义 Plugin，可以通过让 Spring 扫描自定义 Plugin 替代
 * 这里可以用 MyEnginePlugin 替代
 */
@Configuration
public class EngineConfiguration {

    // 这个方法仿照： CamundaBpmConfiguration 中的方法
    @Bean
    public ProcessEngineConfiguration processEngineConfigurationImpl(List<ProcessEnginePlugin> processEnginePlugins,
                                                                     ApplicationContext applicationContext,
                                                                     ApplicationEventPublisher publisher,
                                                                     PlatformTransactionManager transactionManager) {
        ProcessEngineConfigurationImpl configuration = new StandaloneInMemProcessEngineConfiguration();


        if (configuration.getExpressionManager() == null && applicationContext != null) {
            configuration.setExpressionManager(new SpringExpressionManager(applicationContext, configuration.getBeans()));
        }

        CompositeHistoryEventHandler historyEventHandlers = new CompositeHistoryEventHandler();
        historyEventHandlers.add(new DbHistoryEventHandler());
        historyEventHandlers.add(new PublishHistoryEventHandler(publisher));
        configuration.setHistoryEventHandler(historyEventHandlers);

        List<BpmnParseListener> customPostBPMNParseListeners = new ArrayList<>();
        customPostBPMNParseListeners.add(new PublishDelegateParseListener(publisher, new EventingProperty()));
        configuration.setCustomPostBPMNParseListeners(customPostBPMNParseListeners);

        configuration.setIdGenerator(new RandomIdGenerator());


//        configuration.setCustomPreCommandInterceptorsTxRequired(new ArrayList<>());
//        configuration.setCustomPostCommandInterceptorsTxRequired(new ArrayList<>());
//        configuration.setCustomPreCommandInterceptorsTxRequiresNew(new ArrayList<>());
//        configuration.setCustomPostCommandInterceptorsTxRequiresNew(new ArrayList<>());


        configuration.getProcessEnginePlugins().add(new CompositeProcessEnginePlugin(processEnginePlugins));
        return configuration;
    }


    // 这个方法仿照： org.camunda.bpm.engine.spring.SpringTransactionsProcessEngineConfiguration#getDefaultCommandInterceptorsTxRequired
    private List<CommandInterceptor> buildCustomPreCommandInterceptorsTxRequired(PlatformTransactionManager transactionManager,
                                                                                 ProcessEngineConfigurationImpl configuration) {
        List<CommandInterceptor> defaultCommandInterceptorsTxRequired = new ArrayList<CommandInterceptor>();
        return defaultCommandInterceptorsTxRequired;
    }
    private List<CommandInterceptor> buildCustomPostCommandInterceptorsTxRequired(PlatformTransactionManager transactionManager,
                                                                                  ProcessEngineConfigurationImpl configuration) {
        List<CommandInterceptor> defaultCommandInterceptorsTxRequired = new ArrayList<CommandInterceptor>();
        defaultCommandInterceptorsTxRequired.add(new SpringTransactionInterceptor(transactionManager, TransactionTemplate.PROPAGATION_REQUIRED, configuration));

        return defaultCommandInterceptorsTxRequired;
    }
    private List<CommandInterceptor> buildCustomPreCommandInterceptorsTxRequiresNew(PlatformTransactionManager transactionManager) {
        return new ArrayList<>();
    }
    private List<CommandInterceptor> buildCustomPostCommandInterceptorsTxRequiresNew(PlatformTransactionManager transactionManager) {
        return new ArrayList<>();
    }



    @Bean
    public ProcessEngine processEngine(ProcessEngineConfiguration configuration) {
        return configuration.buildProcessEngine();
    }

    @Bean
    public RuntimeService runtimeService(ProcessEngine processEngine) {
        return processEngine.getRuntimeService();
    }

    @Bean
    public RepositoryService repositoryService(ProcessEngine processEngine) {
        return processEngine.getRepositoryService();
    }

    @Bean
    public TaskService taskService(ProcessEngine processEngine) {
        return processEngine.getTaskService();
    }

    @Bean
    public HistoryService historyService(ProcessEngine processEngine) {
        return processEngine.getHistoryService();
    }

    @Bean
    public ManagementService managementService(ProcessEngine processEngine) {
        return processEngine.getManagementService();
    }

    @Bean
    public IdentityService identityService(ProcessEngine processEngine) {
        return processEngine.getIdentityService();
    }

}
